/*
 * IBM Corporation.
 * Copyright (c) 2014 All Rights Reserved.
 */

package com.ibm.iisp.common.util;

import java.security.MessageDigest;
import java.util.Map;
import java.util.Stack;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 类作用：
 * @author Johnny@cn.ibm.com
 * 使用说明：
 */
public class StringUtilsExt {
	static Logger log = LoggerFactory.getLogger(StringUtilsExt.class);
	/**
	 * @param source 将被转换的串，有placeholder的字符串，如<!--action=${action}&user=${userName}&cc=${cc}-->
	 * @param params 用于替换placeholder的值，key是placeholder, value是要置换的目标值，如action=UPDATE, userName=Admin
	 * @return 置换完成后的串，没找到值的placeholder将会保留。如<!--action=UPDATE&user=Admin&cc=${cc}-->
	 */
	public static String replacePlaceHolders(String source, Map<String, String> params) {
		if (params.isEmpty()) {
			return source;
		}
		StringBuilder target = new StringBuilder(source.length() * 2);
		// target.append(source);
		int idx1 = 0;
		int idx2 = source.indexOf("${");
		while (idx2 > 0) {
			target.append(source.substring(idx1, idx2));
			idx1 = source.indexOf("}", idx2);
			String key = source.substring(idx2 + 2, idx1);
			String val = params.get(key);
			if (val == null){
				target.append("${").append(key).append("}");
			} else {
				target.append(val);
			}
			idx1++;
			idx2 = source.indexOf("${", idx1);
		}
		target.append(source.substring(idx1));
		return target.toString();
	}
	
	/**
	 * 把大小写的java property 名字转换为适合数据库的下划线命名习惯。
	 * 
	 * @param oldName
	 *            old prop name
	 * @return 下划线命名
	 */
	public static String toUnderscopeSeperated(String oldName) {
		String regex = "([a-z])([A-Z])";
		String replacement = "$1_$2";
		String newName = oldName.replaceAll(regex, replacement).toLowerCase();
		return newName;
	}
	
	/**
	 * 把一个html从第一个tag开始，截止到和第一个tag对应的闭合tag. 如，从第一个找到的开始，截止到和它对应的
	 * 
	 * @param html
	 *            要截取的html
	 * @return 截取的xhtml
	 */
	public static String trimToEncloseTag(String html){
		Stack<String> tags = new Stack<>();
		int idx = html.indexOf("<") + 1;
		int endTagIdx = idx;
		char char1 = html.charAt(endTagIdx);
		while (char1 != ' ' && char1 != '\t' && char1 != '>'){
			char1 = html.charAt(++endTagIdx);
		}
		String tag = html.substring(idx, endTagIdx);
		while (idx > 0){
			if (html.charAt(idx - 1) == '<'){
				tags.push(tag);
			} else if (html.charAt(idx - 1) == '/'){
				tags.pop();
			}
			if (tags.isEmpty()){
				break;
			}
			idx = html.indexOf(tag, idx + 2);
		}
		return html.substring(0, idx + tag.length() + 1).trim();
	}

	/**
	 * 生成MD5加密串
	 * 
	 * @param s
	 *            要加密的串
	 * @return 加密的串
	 */
	public static String MD5(String s) {
		char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

		try {
			byte[] btInput = s.getBytes();
			// 获得MD5摘要算法的 MessageDigest 对象
			MessageDigest mdInst = MessageDigest.getInstance("MD5");
			// 使用指定的字节更新摘要
			mdInst.update(btInput);
			// 获得密文
			byte[] md = mdInst.digest();
			// 把密文转换成十六进制的字符串形式
			int j = md.length;
			char str[] = new char[j * 2];
			int k = 0;
			for (int i = 0; i < j; i++) {
				byte byte0 = md[i];
				str[k++] = hexDigits[byte0 >>> 4 & 0xf];
				str[k++] = hexDigits[byte0 & 0xf];
			}
			return new String(str);
		} catch (Exception e) {
			log.error("生成MD5串出错！", e);
			return null;
		}
	}

	public static String encodeUnicode(final String str) {
		char[] utfBytes = str.toCharArray();
		String unicodeBytes = "";
		for (int byteIndex = 0; byteIndex < utfBytes.length; byteIndex++) {
			String hexB = Integer.toHexString(utfBytes[byteIndex]); // 转换为16进制整型字符串
			if (hexB.length() <= 2) {
				hexB = "00" + hexB;
			}
			unicodeBytes = unicodeBytes + "\\u" + hexB;
		}
		return unicodeBytes;
	}

	public static String decodeUnicode(final String uniStr) {
		int start = 0;
		int end = 0;
		final StringBuilder buffer = new StringBuilder();
		while (start > -1) {
			end = uniStr.indexOf("\\u", start + 2);
			String charStr = "";
			if (end == -1) {
				charStr = uniStr.substring(start + 2, uniStr.length());
			} else {
				charStr = uniStr.substring(start + 2, end);
			}
			char letter = (char) Integer.parseInt(charStr, 16); // 16进制parse整形字符串。
			buffer.append(new Character(letter).toString());
			start = end;
		}
		return buffer.toString();
	}

	/**
	 * 等价javascript的escape函数，用于保存cookie值。 如：“大ee周?%#@$=” 输出为：“%u5927ee%u5468%3f%25%23%40%24%3d”
	 * 
	 * @param src
	 *            要escape的源串
	 * @return escape后的串
	 */
	public static String escapeJs(String src) {
		int i;
		char j;
		StringBuffer tmp = new StringBuffer();
		tmp.ensureCapacity(src.length() * 6);
		for (i = 0; i < src.length(); i++) {
			j = src.charAt(i);
			if (Character.isDigit(j) || Character.isLowerCase(j)
				|| Character.isUpperCase(j)) {
				tmp.append(j);
			}
			else if (j < 256) {
				tmp.append("%");
				if (j < 16) {
					tmp.append("0");
				}
				tmp.append(Integer.toString(j, 16));
			} else {
				tmp.append("%u");
				tmp.append(Integer.toString(j, 16));
			}
		}
		return tmp.toString();
	}

	/**
	 * 等价javascript的unescape函数，用于从cookie值中还原值。 如：“%u5927ee%u5468%3f%25%23%40%24%3d” 输出为：“大ee周?%#@$=”
	 * 
	 * @param src
	 *            要unescape的源串
	 * @return unescape后的串
	 */
	public static String unescapeJs(String src) {
		StringBuffer tmp = new StringBuffer();
		tmp.ensureCapacity(src.length());
		int lastPos = 0, pos = 0;
		char ch;
		while (lastPos < src.length()) {
			pos = src.indexOf("%", lastPos);
			if (pos == lastPos) {
				if (src.charAt(pos + 1) == 'u') {
					ch = (char) Integer.parseInt(src
						.substring(pos + 2, pos + 6), 16);
					tmp.append(ch);
					lastPos = pos + 6;
				} else {
					ch = (char) Integer.parseInt(src
						.substring(pos + 1, pos + 3), 16);
					tmp.append(ch);
					lastPos = pos + 3;
				}
			} else {
				if (pos == -1) {
					tmp.append(src.substring(lastPos));
					lastPos = src.length();
				} else {
					tmp.append(src.substring(lastPos, pos));
					lastPos = pos;
				}
			}
		}
		return tmp.toString();
	}

}
